import java.io.*;
import java.net.*;

/**
* Modulo que contiene la l�gica de aplicaci�n de un Servidor Concurrente que utiliza
* una clase de envoltura de Socket que contiene
* m�todos para mandar y recibir mensajes.
* @bibliography: Computacion Distribuida. M. L. Lio. Pearson-Addison Wesley. pp 154-156.
* @author: M. L. Liu
*/
public class servidor_dinamico {
  private int puerto; // puerto de conexi�n.
  private int maxcon; // n�mero de sesiones multiples m�ximo
  private int numcon; // n�mero de sesiones abiertas

  /**
  * Constructor que recibe el puerto de conexi�n y el n�mero m�ximo de clientes que atiende simult�neamente
  */
  servidor_dinamico(int puerto_in, int maxcon_in) {
    puerto = puerto_in;
    maxcon = maxcon_in;
    numcon = 0;
  } // servidor_dinamico


  /**
  * M�todo en exclusi�n mutua para disminuir el n�mero de sesiones abiertas
  */
  public synchronized void subnumcon() {
    numcon--;
  } // subnumcon

  /**
  * M�todo en exclusi�n mutua para aumnetar el n�mero de sesiones abiertas
  */
  private synchronized void addnumcon() throws Exception {
    numcon++;
  } // addnumcon

  /**
  * M�todo para crear las conexiones con cada cliente que lo solicite
  */
  public void run() {
    try {
      // instancia un socket para aceptar la conexi�n
      ServerSocket SocketConexion = new ServerSocket(puerto);
      System.out.println("Servidor Principal escuchando el puerto " + puerto);

      while (true) {
        // Comprobar si existen conexiones libres
        while (numcon == maxcon) {
          System.out.println("Servidor Full");
          synchronized(this) {
            try {
              this.wait(10000);
            } catch (Exception e) // Imprimir cualquier excepcion
            { /* System.err.println(e); */ }
          }
        } // while ...

        // espera una petici�n de conexi�n, instante en el cual
        // se lanza un hilo que se encarga de la comunicaci�n con el cliente
        SocketBytes SocketDatos = new SocketBytes(SocketConexion.accept());

        // Indicar que hay una conexi�n libre menos
        addnumcon();

        // Arrancar hilo que atiende esta conexion por el Socket SocketDatos y recibe este objeto para actualizar
        // el n�mero de conexiones libres.
        hilo h = new hilo(SocketDatos, this);
        h.start();        
      } // while ...
    } catch (Exception e) // Imprimir cualquier excepci�n
    { System.err.println(e); }
  } // run

  public static void main(String args[]) throws NumberFormatException {
    if (args.length != 2) {
      System.out.println("Necesito 2 argumentos con puerto de conexi�n y m�ximo n�mero de conexiones con clientes");
      System.exit(1);
    } // if ...

    int puerto = Integer.parseInt(args[0]);
    System.out.println("Puerto de conexion con servidor  = " + puerto);
    
    int maxnumcon = Integer.parseInt(args[1]);
    System.out.println("M�ximo n�mero conexiones  = " + maxnumcon);
    
    servidor_dinamico sd = new servidor_dinamico(puerto, maxnumcon);

    sd.run();
  } // main
} // servidor_dinamico
